﻿using System.Collections.Generic;
using System.ComponentModel;
using System.Web.UI;
using System.Web.UI.HtmlControls;
[assembly: WebResource("ModulesToolkit.Web.UI.Popup.Popup.js", "text/JavaScript")]

namespace ModulesToolkit.Web.UI
{
    /// <summary>
    /// Summary description for ServerControl1
    /// </summary>
    public class Popup : ScriptControl, IPostBackEventHandler, INamingContainer
    {
        #region Contants

        private const string DefaultCssClass = "Popup";

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the validation group.
        /// </summary>
        /// <value>
        /// The validation group.
        /// </value>
        public string ValidationGroup
        {
            set { this.ViewState.Set("ValidationGroup", value); }
            get { return this.ViewState.Get("ValidationGroup", string.Empty); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether [causes validation].
        /// </summary>
        /// <value>
        ///   <c>true</c> if [causes validation]; otherwise, <c>false</c>.
        /// </value>
        public bool CausesValidation
        {
            set { this.ViewState.Set("CausesValidation", value); }
            get { return this.ViewState.Get("CausesValidation", true); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this instance is model.
        /// </summary>
        /// <value>
        ///   <c>true</c> if this instance is model; otherwise, <c>false</c>.
        /// </value>
        public bool IsModel
        {
            set { this.ViewState.Set("IsModel", value); }
            get { return this.ViewState.Get("IsModel", true); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this instance is draggable.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is draggable; otherwise, <c>false</c>.
        /// </value>
        public bool IsDraggable
        {
            set { this.ViewState.Set("IsDraggable", value); }
            get { return this.ViewState.Get("IsDraggable", false); }
        }

        #region Overrides
        /// <summary>
        /// Gets the <see cref="T:System.Web.UI.HtmlTextWriterTag"/> value that corresponds to this Web server control. This property is used primarily by control developers.
        /// </summary>
        /// <returns>One of the <see cref="T:System.Web.UI.HtmlTextWriterTag"/> enumeration values.</returns>
        protected override HtmlTextWriterTag TagKey
        {
            get
            {
                return HtmlTextWriterTag.Div;
            }
        }

        /// <summary>
        /// Gets or sets the Cascading Style Sheet (CSS) class rendered by the Web server control on the client.
        /// </summary>
        /// <returns>The CSS class rendered by the Web server control on the client. The default is <see cref="F:System.String.Empty"/>.</returns>
        public override string CssClass
        {
            get
            {
                if (!string.IsNullOrWhiteSpace(base.CssClass))
                    return base.CssClass;
                return DefaultCssClass;
            }
        }
        #endregion

        #region Header Properties

        /// <summary>
        /// Gets or sets a value indicating whether [allow close].
        /// </summary>
        /// <value>
        ///   <c>true</c> if [allow close]; otherwise, <c>false</c>.
        /// </value>
        public bool AllowClose
        {
            set { this.ViewState.Set("AllowClose", value); }
            get { return this.ViewState.Get("AllowClose", true); }
        }
        /// <summary>
        /// Gets or sets the close image URL.
        /// </summary>
        /// <value>
        /// The close image URL.
        /// </value>
        public string CloseImageUrl
        {
            set { this.ViewState.Set("CloseImageUrl", value); }
            get { return this.ViewState.Get("CloseImageUrl", string.Empty); }
        }
        /// <summary>
        /// Gets or sets the title.
        /// </summary>
        /// <value>
        /// The title.
        /// </value>
        public string Title
        {
            set { this.ViewState.Set("Title", value); }
            get { return this.ViewState.Get("Title", string.Empty); }
        }

        #endregion

        #region Content Properties
        /// <summary>
        /// Gets or sets the content text.
        /// </summary>
        /// <value>
        /// The content text.
        /// </value>
        public string ContentText
        {
            set { this.ViewState.Set("ContentText", value); }
            get { return this.ViewState.Get<string>("ContentText"); }
        }
        #endregion

        #region Templates
        [PersistenceMode(PersistenceMode.InnerProperty)]
        [Browsable(false)]
        [TemplateInstance(TemplateInstance.Single)]
        public ITemplate ContentTemplate
        {
            get;
            set;
        }

        [PersistenceMode(PersistenceMode.InnerProperty)]
        [Browsable(false)]
        [TemplateInstance(TemplateInstance.Single)]
        public ITemplate FooterTemplate
        {
            set;
            get;
        }

        [PersistenceMode(PersistenceMode.InnerProperty)]
        [Browsable(false)]
        [TemplateInstance(TemplateInstance.Single)]
        public ITemplate HeaderTemplate
        {
            set;
            get;
        }
        #endregion

        #endregion Properties

        #region Methods

        /// <summary>
        /// When implemented by a class, enables a server control to process an event raised when a form is posted to the server.
        /// </summary>
        /// <param name="eventArgument">A <see cref="T:System.String"/> that represents an optional event argument to be passed to the event handler.</param>
        public void RaisePostBackEvent(string eventArgument)
        {
            if (eventArgument == "close")
            {
                // cannot use and in this condition, cuz IsValid will crash unless the cause validation is true.
                if (this.CausesValidation)
                {
                    this.Page.Validate(this.ValidationGroup);
                    if (this.Page.IsValid)
                        this.Hide();
                }
                else
                    this.Hide();
            }
        }

        /// <summary>
        /// Hides this instance.
        /// </summary>
        public void Hide()
        {
            this.Visible = false;
        }

        /// <summary>
        /// Shows this instance.
        /// </summary>
        public void Show()
        {
            this.Visible = true;
        }

        #region Overrides

        protected override void OnInit(System.EventArgs e)
        {
            base.OnInit(e);
            this.EnsureChildControls();
        }

        /// <summary>
        /// Raises the <see cref="E:System.Web.UI.Control.Load"/> event.
        /// </summary>
        /// <param name="e">The <see cref="T:System.EventArgs"/> object that contains the event data.</param>
        protected override void OnLoad(System.EventArgs e)
        {
            base.OnLoad(e);
            // default must be hidden
            if (!this.Page.IsPostBack)
                this.Hide();
        }
        /// <summary>
        /// Adds HTML attributes and styles that need to be rendered to the specified <see cref="T:System.Web.UI.HtmlTextWriterTag"/>. This method is used primarily by control developers.
        /// </summary>
        /// <param name="writer">A <see cref="T:System.Web.UI.HtmlTextWriter"/> that represents the output stream to render HTML content on the client.</param>
        protected override void AddAttributesToRender(HtmlTextWriter writer)
        {
            base.AddAttributesToRender(writer);
            writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssClass);
            writer.AddAttribute(HtmlTextWriterAttribute.Width, this.Width.ToString());
            writer.AddAttribute(HtmlTextWriterAttribute.Height, this.Height.ToString());
        }
        /// <summary>
        /// When overridden in a derived class, returns the <see cref="T:System.Web.UI.ScriptDescriptor"/> objects for the control.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Collections.IEnumerable"/> collection of <see cref="T:System.Web.UI.ScriptDescriptor"/> objects.
        /// </returns>
        protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors()
        {
            ScriptControlDescriptor descriptor = new ScriptControlDescriptor("ModulesToolkit.Web.UI.Popup", this.ClientID);
            descriptor.AddProperty("IsModel", IsModel);
            descriptor.AddProperty("IsDraggable", IsDraggable);
            yield return descriptor;
        }
        /// <summary>
        /// When overridden in a derived class, returns the script files for the control.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Collections.IEnumerable"/> collection that contains ECMAScript (JavaScript) files that have been registered as embedded resources.
        /// </returns>
        protected override IEnumerable<ScriptReference> GetScriptReferences()
        {
            yield return new ScriptReference("ModulesToolkit.Web.UI.Popup.Popup.js", this.GetType().Assembly.FullName);
        }
        /// <summary>
        /// Called by the ASP.NET page framework to notify server controls that use composition-based implementation to create any child controls they contain in preparation for posting back or rendering.
        /// </summary>
        protected override void CreateChildControls()
        {
            var header = BuildHeaderControl();
            var content = BuildContentControl();
            var footer = BuildFooterControl();
            this.Controls.Add(header);
            this.Controls.Add(content);
            this.Controls.Add(footer);
            //-----------------------------------
            base.CreateChildControls();
        }
        #endregion

        #region Helpers
        /// <summary>
        /// Gets the post back options.
        /// </summary>
        /// <returns></returns>
        protected virtual PostBackOptions GetPostBackOptions()
        {
            PostBackOptions postBackOptions = new PostBackOptions(this, "close");
            postBackOptions.ClientSubmit = true;
            postBackOptions.AutoPostBack = true;
            if (this.CausesValidation && this.Page != null && this.Page.GetValidators(this.ValidationGroup).Count > 0)
            {
                postBackOptions.PerformValidation = true;
                postBackOptions.ValidationGroup = this.ValidationGroup;
            }
            return postBackOptions;
        }

        /// <summary>
        /// Builds the header control.
        /// </summary>
        /// <returns></returns>
        private Control BuildHeaderControl()
        {
            var divHeader = new HtmlGenericControl("div");
            divHeader.Attributes.Add("class", "popup__header");
            if (this.HeaderTemplate != null)
            {
                this.HeaderTemplate.InstantiateIn(divHeader);
            }
            else
            {
                var span = new HtmlGenericControl("span");
                span.InnerText = this.Title;
                divHeader.Controls.Add(span);
                //-----------------------------------------------
                if (this.AllowClose)
                {
                    var divCloseButtonContainer = new HtmlGenericControl("div");
                    divCloseButtonContainer.Attributes.Add("class", "popup__header_CloseButton");
                    HtmlImage img = new HtmlImage();
                    img.Attributes.Add("onclick",
                                       this.Page.ClientScript.GetPostBackEventReference(this.GetPostBackOptions()));
                    img.Src = this.Page.ResolveClientUrl(this.CloseImageUrl);
                    divCloseButtonContainer.Controls.Add(img);
                    divHeader.Controls.Add(divCloseButtonContainer);
                }
            }
            return divHeader;
        }

        /// <summary>
        /// Builds the content control.
        /// </summary>
        /// <returns></returns>
        private Control BuildContentControl()
        {
            var divContent = new HtmlGenericControl("div");
            divContent.Attributes.Add("class", "popup__content");
            if (this.ContentTemplate != null)
            {
                this.ContentTemplate.InstantiateIn(divContent);
            }
            else
            {
                var span = new HtmlGenericControl("span");
                span.InnerText = this.ContentText;
                divContent.Controls.Add(span);
            }
            return divContent;

        }

        /// <summary>
        /// Builds the footer control.
        /// </summary>
        /// <returns></returns>
        private Control BuildFooterControl()
        {
            var divFooter = new HtmlGenericControl("div");
            divFooter.Attributes.Add("class", "popup__footer");
            if (this.FooterTemplate != null)
            {
                this.FooterTemplate.InstantiateIn(divFooter);
            }
            return divFooter;
        }
        #endregion

        #endregion Methods
    }
}